#include <ConnectionBroker/server/LongPollServer.h>
#include <ConnectionBroker/clientconnection/LongPollConnection.h>
#include <ConnectionBroker/clientconnection/LongPollClientConnection.h>
#include <boost/bind.hpp>
#include <boost/random/random_device.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/shared_ptr.hpp>

using namespace ConnectionBroker;
using boost::asio::ip::tcp;

LongPollServer::LongPollServer(const ConnectionBroker::ServerSettings& settings, 
                     serverCallback pDefaultCallback, 
                     serverCallback pDefaultClientConnectCallback,
                     serverCallback pDefaultClientDisconnectCallback
                    ) 
: Server(settings, 
         pDefaultCallback, 
         pDefaultClientConnectCallback,
         pDefaultClientDisconnectCallback
        ), 
         mNextClientId(1), 
         mIoService(),
         mAcceptor(mIoService, tcp::endpoint(tcp::v4(), settings.port()))

{
}

LongPollServer::~LongPollServer()
{
}

LongPollClientConnectionPtr LongPollServer::idPassToClient(const int id, const std::string& pass)
{
   std::pair<int, std::string> idPassPair = std::make_pair(id, pass);
   if(!mIdPassClientMap.count(idPassPair))
      return LongPollClientConnectionPtr();

   return mIdPassClientMap[idPassPair];
}

LongPollClientConnectionPtr LongPollServer::longPollClientFactory()
{
   //Create the new client, incrementing the id.
   LongPollClientConnectionPtr pClient(new LongPollClientConnection(this, mIoService, mNextClientId++, generatePassword()));

   //Insert the client into the client list.
   addClient(pClient);

   mIdPassClientMap[std::make_pair(pClient->id(), pClient->pass())] = pClient;

   return pClient;
}

void LongPollServer::longPollClientRemove(LongPollClientConnectionPtr pClient)
{
   mIdPassClientMap.erase(std::make_pair(pClient->id(), pClient->pass()));
   removeClient(pClient);
}

std::string LongPollServer::generatePassword()
{
   int passLen = 10;
   std::string out;
   std::string alphanum(
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz");

   boost::random::random_device rng;
   boost::random::uniform_int_distribution<> index_dist(0, alphanum.size() - 1);
   for(int i = 0; i < passLen; ++i)
      out.append(1, alphanum[index_dist(rng)]);

   return out;
}

void LongPollServer::handleAccept(const boost::system::error_code& error)
{
   if(error)
   {
      startAcceptingClients();
      return;
   }

   mNextConnection->start();
   startAcceptingClients();
}

void LongPollServer::startAcceptingClients()
{
   mNextConnection.reset(new LongPollConnection(mIoService, this));
   mAcceptor.async_accept(mNextConnection->socket(), boost::bind(&LongPollServer::handleAccept, this, boost::asio::placeholders::error));
}

void LongPollServer::start()
{
   startAcceptingClients();
   mIoService.run();
}

